<!-- -->
<HTML>
<TITLE>Smart Proxies</TITLE>
<BODY>

<BODY text = "#000000"
link="#000fff"
vlink="#ff0f0f"
bgcolor="#ffffff">

<Hr><P>
<H3>Smart Proxies</H3>

<P>Smart Proxies are a meta-programming extension supported by TAO
that provides user-defined proxy classes.  By default TAO's IDL
compiler generates proxy classes for IDL interfaces.  The proxy is an
exact image of the target object on whom the invocations are to be
made by the client, i.e., it has the same methods as the targeting
interface. A proxy packages the request which gets marshalled and
sent to the target object.  A paper that describes TAO's <A
HREF="interceptors.html">portable interceptor</A> and smart proxy
support is available <A
HREF="http://www.dre.vanderbilt.edu/~schmidt/PDF/smart_proxies.pdf">online</A>.</p></p>

<Hr><P>
<h3><a name="toc">Table of Contents</a></h3>
<ul>
  <li><a href="#Examples">Examples</a>
  <li><a href="#Design Issues">Design Issues</a>
  <li><a href="#Design Overview">Design Overview</a>
  <li><a href="#Inheritance">Inheritance Issues</a>
  <li><a href="#Implementation Issues">Implementation Issues</a>
  <li><a href="#Options">Usage Options</a>
  <li><a href="#Acknowledgements">Acknowledgements</a>
  <li><a href="#ref">References</a>
</ul>

<Hr><P>
<h3><a name="Examples">Examples</a></h3>

<P>The user may wish to manually change the proxy code for the following
reasons:

<UL> <LI> Cache information about the remote object locally to save
the expense of going across the wire for every request. <P>

<LI> Batch updates/accesses to the remote object.
<p>For instance:<br>
Consider a remote Database which has an API which can update either a
single record or 10 records at one shot. To leverage performance, one
would want to use this method. So a user can use the smart proxy to
implement the 10 record update method by caching single record update
requests.</p>

<P>It is not certain whether this usecase might not induce extra
overhead and whether the proxy can be smart enough to deduce the use
of this kind of batch processing. Also, this scheme wont work for
two-way calls.The "cached-oneways" feature might make more sense in
this scenario. Thus the application programmer will have to determine
how this caching optimization changes the semantics of the original
interface.</p>

<LI> The client can make a single request which results in a sequence
of invocations to one or possibly more objects.

<p> For instance:<br>
The smart stub has some private methods (since this is user specific
this should be possible) which do validation of the request to be
made. The remote call could result in another call wherein the
validation occurs before it is shoved over the wire.</p>

<LI> Quality of Service features like load-balancing can be considered
by the smart proxy before making the invocation on the appropriate
target object.</p>
</UL>

<Hr><P>
<h3><a name="Design Issues">Design Issues</a></h3>

<UL>
<LI> How will the smart proxy be created?
<LI> Who will create the smart proxy?
<LI> It has to be done before the invocations on the target object are
done, so when will it get created?
<LI> What about collocation? Will those stubs fall under this category?
<LI> Will smart proxies work for collocated object references?
</UL>

<h3>Design Needs and discussion points</h3>

<P>A ProxyFactory (either default or user-defined) is needed which
will create the stubs (either default or smart). This factory should
be able to create different kinds of proxies.</p>

<P>The <code>unchecked_narrow</code> method needs to return the
appropriate stub.</p>

<P>Collocated stubs need to be handled too. This means that smart
proxies need to be generated for collocated object references too.</p>

<P>An existing function for creating stubs has to replaced by a class
which will handle all cases viz. default stubs, smart stubs (proxies),
collcated stubs.</p>

<h2><a name="Design Overview">Design Overview</a></h2>

<P>At a glance:</p>

<P>Classses to be generated by TAO_IDL in addition to the Default
Stub:</p>

<UL>
<LI> <CODE>TAO_Proxy_Factory_Adapter</CODE>
<p>The singleton which has the different proxies (stubs) factories
registered with it.</p>

<LI> <CODE>TAO_Test_Default_Proxy_Factory</CODE>
<p>The factory which returns the proxy_ptr which is used in the
<code>unchecked_narow</code> method to create the appropriate proxy
object.

<LI> <CODE>TAO_Smart_Proxy_Base</CODE>
<p>The smart proxy interface which makes it easier for the
user to simply implement only the methods he wishes to change and also
provides a <br>common interface to address remote as well as collocated
stubs.</p>
</UL>

<P>Classes to be defined by the user:</p>

<UL>
<LI> <CODE>SmartFactory</CODE> - inherits from TAO_Default_Proxy_Factory class.
<p>The factory which will create the smart proxy which the
user wants. Its necessary that an object of this class is created.</p>

<LI> <CODE>SmartProxy</CODE> - derivative of the TAO_Smart_Proxy_Base class.
<p>The proxy which has the user desired extra functionality.</p>

<P>*Note: Names are as they are to make it easier to comprehend the
concept.</p>
</UL>

<Hr><P>
<h3>Detailed Example</h3>

<pre>
//------------------------ Generated by TAO_IDL------------------------

class TAO_Proxy_Factory_Adapter
{
 // DESCRIPTION:
 // Behaves like a singleton and contains the
 // factory object which is used to create the
 // default/smart Proxys.
public:

 friend class ACE_Singleton<TAO_Proxy_Factory_Adapter, TAO_SYNCH_RECURSIVE_MUTEX>;

 // Register the factory with the Adaptor.
 register_proxy (TAO_Default_Proxy_Factory *df)
 {
   Perform Double-Checked Locking Optimisation...

   // If there is a factory already existing, replace it.
   this->unregister_proxy_factory ();
   this->proxy_factory_ = df;
   this->delete_proxy_factory_ = 0;
 }

 // Remove the factory.
 unregister_proxy_factory (void)
 {
   Perform Locking to ensure exclusive access.
    if (this->delete_proxy_factory_ == 0 && this->proxy_factory_ != 0)
    {
      // Its necessary to set <delete_proxy_factory_> to 1 to make sure that it
      // doesnt get into an infinite loop in <unregister_proxy_factory> as it is
      // invoked in the destructor of the class too.
      this->delete_proxy_factory_ = 1;
      delete this->proxy_factory_;
      this->proxy_factory_ = 0;
    }
 }

 // Delegation of the Proxy creation to the factory
 interface_ptr create_proxy (void)
 {
   Verify that an <proxy_factory_> is available else make one.

   return this->factory_->create_proxy ();
 }

protected:

 TAO_Test_Default_Proxy_Factory *proxy_factory_;
 int delete_proxy_factory_;
 TAO_SYNCH_RECURSIVE_MUTEX lock_;

};

// This class will also be generated by TAO_IDL.
class TAO_Default_Proxy_Factory
{
 // DESCRIPTION:
 // This class is the parent for the different Proxy factories. The
 // Proxy could either be collocated or remote and hence here only
 // the Proxy pointer is returned which will be created on invocation of
 // <unchecked_narrow>.

public:
 TAO_Default_Proxy_Factory (int register_proxy_factory);
 {
   // Unless told don't register. By default registration is done.
   // This comes in handy while creating the TAO_Proxy_Factory_Adapter
   // instance since we want either the user to set the factory. Only
   // if that doesnt happen will the TAO_Default_Proxy_Factory be set
   // to the factory delegated by the Adapter and that is done using
   // the Lazy Evaluation Principle when the first call to <create_proxy>
   // is done.

   if (register_proxy_factory)
    {
      TAO_PROXY_FACTORY_ADAPTER::instance ()->register_proxy_factory (this);
    }
 }

 ~TAO_Default_Proxy_Factory (void)
 {
 }

 // By default the proxy is simply returned.
 interface_ptr create_proxy (interface_ptr proxy)
 {
   return proxy;
 }

};

// This class will be generated by the TAO_IDL.
class TAO_Smart_Proxy_Base : public virtual DefaultProxyInterface
{
 // DESCRIPTION:
 // This class is the class from which the user will inherit
 // and simply override the methods he requires. This extra
 // level of indirection is necessary to be able to provide
 // the smartProxy interface for even collocated Proxies.
public:

 // The delegation to which underlying proxy is decided here.
 TAO_Smart_Proxy_Base (interface_ptr proxy)
  : base_proxy_ (proxy)

 // Interface operations...
 int method ()
  {
    this->proxy_->method ();
  }
 ...
 // @@ How are exceptions handled?
 // This not an issue really because the actual method call is simply
 // to the application level which is catch it as the exception is
 // propagated upwards from the proxy level.

protected:
 // This var member denotes the kind of proxy used:
 // collacated-thru_poa, collocated-direct, or remote.
 // This is decided by the collocated strategy used along
 // with the smart Proxies. Note: the collocated Proxies
 // themselves are smart proxies. The proxy pointer passed
 // thru the constructor will be assigned to <proxy_>. The
 // pointer will actually point to the smart proxy in case
 // of smart proxies or else to the default proxy.
  DefaultProxyInterface_var base_proxy_;

};

// ----------------- User Implementation Begins here----------------

// Note: This has to be implemented by the user
class SmartFactory : public TAO_Default_Proxy_Factory
{
 // DESCRIPTION:
 // An object of this class has to be defined by the user
 // which will cause it to be registered with the
 // ProxyFactoryAdaptor.
public:

 Smartinterface_ptr create_proxy (interface_ptr proxy)
 {
   return (!CORBA::is_nil (proxy) ? new SmartProxy (proxy) : proxy);
  }
};

// This class will be implemented by the user.
class VerySmartProxy : public TAO_Smart_Proxy_Base
{
 // DESCRIPTION:
 // This is the smart Proxy will is defined by the user
 // to suit his needs.
 int method ()
 {
   print "Yahoo, I am so smart"
   this->proxy_->method ();
 }

}

// --------------------Related Stub Changes------------------


// Generated by TAO_IDL. Note the changes wherein the
// TAO_Proxy_Factory_Adapter is used.

interface_ptr _unchecked_narrow (CORBA::Object obj,
                                 CORBA::Environment &)
{
   if (CORBA::is_nil (obj))
        return test::_nil ();
      TAO_Proxy* Proxy = obj->_stubobj ();
      stub->_incr_refcnt ();
      interface_ptr *default_proxy = interface::_nil ();

      if (obj->_is_collocated () && _TAO_collocation_interface_Stub_Factory_function_pointer != 0)
        {
          default_proxy =
            _TAO_collocation_interface_Stub_Factory_function_pointer (obj);
        }

      if (CORBA::is_nil (default_proxy))
        ACE_NEW_RETURN (default_proxy, interface (stub), test::_nil ());

      return TAO_PROXY_FACTORY_ADAPTER::instance ()->create_proxy (default_proxy);
    }
}
</pre>

<Hr><P>
<h3><a name="Inheritance">Inheritance Issues</a></h3>
<p>The original implementation of the Smart Proxies was cumbersome
since when a smart proxy inherited from another the constructor
explicitly had to call the constructor of the base class of the other
proxy. To get over this issue, implementation inheritance was applied
by <a href="mailto:brian.wallis@ot.com.au">Brian Wallis</a> where
there is a higher level Smart_Proxy_Base which stores the
<CODE> base_proxy_ </CODE> member. This implementation was influenced
by a similar implementation in Orbix. Thanks to Brian Wallis for this
wonderful contribution to Smart Proxies in TAO.

<p>This design was modified slightly and now every interface smart
proxy base class holds a <CODE> proxy_ </CODE> member which is the
narrowed version of the <CODE> base_proxy_ </CODE>. This way every call
neednt have to go through the narrowing process as the
<CODE>base_proxy_</CODE> is stored as a CORBA_Object_var while we need
the interface pointer to make the desired invocations.

<Hr><P>
<h3><a name="Implementation Issues">Implementation Issues</a></h3>

<UL>
<LI> Native exceptions? How are these to be handled?</p>
<p> This not an issue really because the actual method call is simply
to the application level which will catch it as the exception is
propagated upwards from the proxy level.</p>

<LI> What if the user wants to have a smart proxy which inherits from
many interfaces?
<p> First have different smart proxies which inherit from the
TAO_Smart_Proxy_Base (every default smart proxy is for an interface) and
then have a new smart proxy inheriting from the previously created
smart proxies. But remember: the SmartProxyFactory should create the
final smart proxy thru its create_proxy () method.</p>

<LI> Do I need to create a Smart Proxy Factory every time I use a
smart proxy?
<p> Yes, you do. Once the Smart Proxy Factory is created, it is
automatically used to create the proxy and thus a smart proxy is
obtained instead of the default one. When the smart proxy makes its
first invocation, this factory is unregistered. So all the proxies
created from then on will be the default one.
</UL>

<Hr><P>
<h3><a name="Options">Usage Options</a></h3>
<p> To use this feature in TAO, one must do the following:
(1) Generate smart proxy classes using the IDL compiler option of
-Gsp and (2) Link client and server to the TAO_SmartProxies library, in
$TAO_ROOT/tao/SmartProxies.
A new smart proxy option has been added to the design: one-shot or
permanent versus per-object smart proxy.  The one-shot smart proxy
option denotes that the smart proxy factory is registered permanently
and so for all object instances the same kind of proxy is used.  On
disabling this default option one can achieve the use of different
smart proxies for every object instead of every interface.
For details please see the paper on
<a href="http://www.dre.vanderbilt.edu/~schmidt/PDF/COOTS-00.pdf">
Meta-programming Mechanisms for ORB Middleware as well as the test at
$TAO_ROOT/tests/Smart_Proxies/Policy.

<Hr><P>
<h3><a name="Acknowledgements">Acknowledgements</a></h3>

<P><a href="mailto:nanbor@cs.wustl.edu">Nanbor Wang</a> and <a
href="mailto:d.schmidt@vanderbilt.edu">Dr.Schmidt</a> for their help in
designing and discussing this feature. <P>

<P><a href="mailto:brian.wallis@ot.com.au">Brian Wallis</a> for
contributing the implementation inheritance feature.

<Hr><P>
<h3><a name="ref">References</a></h3>

<p> CORBA Distributed Objects using Orbix - Sean Baker </p>
<p> Visigenic Documentation </p>
<p> Orbix Documentation </p>

<Hr><P>
<p><h3>Last Update</h3></3>

<p> Date: 02Jul2001</p>
<p> By: <a href="mailto:parsons@cs.wustl.edu">Jeff Parsons</a></p>

</BODY>
</HTML>
